package cn.lbd.api.stream;

import cn.lbd.api.lambda.Employee;
import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;


public class TestStreamAPIDemo1 {
    private List<Employee> lists = Arrays.asList(
            new Employee(12, "张三", 9999.99, Employee.Status.BUSY),
            new Employee(48, "胡时飞", 6000.11, Employee.Status.BUSY),
            new Employee(22, "李四", 8888.88, Employee.Status.FREE),
            new Employee(62, "王五", 6999.99, Employee.Status.VOCATION),
            new Employee(47, "贾科斯", 4999.11, Employee.Status.FREE)
    );

    @Test
    public void test1() {
        Stream<Employee> stream1 = lists.stream();

        Employee[] employees = new Employee[10];
        Stream<Employee> stream2 = Arrays.stream(employees);

        Stream<String> stream3 = Stream.of("aa", "bb", "cc");

        Stream<Integer> stream = Stream.iterate(0, (x) -> x + 2);
        stream.limit(10).forEach(System.out::println);

        Stream.generate((Math::random))
                .limit(5)
                .forEach(System.out::println);

        Iterator<Employee> iterator = lists.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

    @Test
    public void test2() {
        lists.stream()
                .filter((e) -> {
                    /*System.out.println("短路");*/
                    return e.getSalary() > 3000;
                })
                .distinct()
                .forEach(System.out::println);
    }

    @Test
    public void test3() {
        List<String> strings = Arrays.asList("aaa", "bbb", "ccc", "ddd");
        strings.stream()
                .map(s -> s.toUpperCase())
                .forEach(System.out::println);

        lists.stream()
                // 类名::实例对象 的方法引用方式  方法的调用者是Employee,第二个参数为空，满足（类名::实例对象）的条件
                /*.map(employee -> employee.getName())*/
                .map(Employee::getName)
                //对象::实例方法
                .forEach(System.out::println);
    }

    @Test
    public void test4() {
        List<String> strings = Arrays.asList("aaa", "bbb", "ccc", "ddd");
        /*Stream<Stream<Character>> streams = strings.stream()
                .map(TestStreamAPIDemo1::execute);
        streams.forEach((stream) ->{
            stream.forEach(System.out::println);
        });*/

        Stream<Character> stream = strings.stream()
                .flatMap(TestStreamAPIDemo1::execute);
        stream.forEach(System.out::println);
    }

    public static Stream<Character> execute(String str) {
        List<Character> list = new ArrayList<>();
        for (Character character : str.toCharArray()) {
            list.add(character);
        }
        return list.stream();
    }

    @Test
    public void test5() {
        List strings = Arrays.asList("aaa", "bbb", "ccc", "ddd");

        List list = new ArrayList();
        list.add(1);
        list.add(2);
        list.addAll(strings);
        System.out.println(list.toString());
    }

    @Test
    public void test6() {
        lists.stream()
                .sorted((x, y) -> {
                    if (x.getAge().equals(y.getAge())) {
                        return x.getSalary().compareTo(y.getSalary());
                    } else {
                        return -x.getAge().compareTo(y.getAge());
                    }
                })
                .forEach(System.out::println);
    }


    /**
     * allMatch：检查是否匹配所有元素
     * anyMatch：检查是否至少匹配一个元素
     * noneMatch：检查是否没有匹配所有元素
     * findFirst：返回第一个元素
     * findAny：返回当前流中的任意元素
     * count：返回流中元素的总个数
     * max：返回流中最大值
     * min：返回流中最小值
     */
    @Test
    public void test7() {
        boolean flag1 = lists.stream()
                .allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(flag1);
        boolean flag2 = lists.stream()
                .anyMatch((e) -> e.getStatus().equals(Employee.Status.FREE));
        System.out.println(flag2);
        boolean flag3 = lists.stream()
                .noneMatch((e) -> e.getStatus().equals(Employee.Status.VOCATION));
        System.out.println(flag3);

        Optional<Employee> op1 = lists.stream()
                .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
                .findFirst();
        System.out.println(op1.get());

        Optional<Employee> op2 = lists.stream()
                .filter(employee -> employee.getStatus().equals(Employee.Status.BUSY))
                .findAny();
        System.out.println(op2.get());

        long count = lists.stream()
                .filter(employee -> employee.getStatus().equals(Employee.Status.BUSY))
                .count();
        System.out.println(count);

        Optional<Employee> min = lists.stream()
                .min((x, y) -> Integer.compare(x.getAge(), y.getAge()));
        System.out.println(min);

        Optional<Integer> max = lists.stream()
                .map(Employee::getAge)
                .max(Integer::compareTo);
        System.out.println(max.get());
    }

    @Test
    public void test8() {

        Double sum = lists.stream()
                .map(Employee::getSalary)
                .reduce(0.0, Double::sum);
        System.out.println(sum);

        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Optional<Integer> op1 = list.stream()
                .reduce((x, y) -> x + y);
        System.out.println(op1);

        List<Double> collect = lists.stream()
                .map(Employee::getSalary)
                .collect(Collectors.toList());
        System.out.println(collect.toString());


        HashSet<Employee> collect1 = lists.stream()
                .collect(Collectors.toCollection(HashSet::new));

        Long collect2 = lists.stream()
                .collect(Collectors.counting());
        System.out.println(collect2);

        Double collect3 = lists.stream()
                .collect(Collectors.averagingDouble((x) -> x.getSalary()));
        System.out.println(collect3);

        Integer collect4 = lists.stream()
                .collect(Collectors.summingInt(Employee::getAge));
        System.out.println(collect4);

        Optional<Employee> max = lists.stream()
                .collect(Collectors.maxBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));
        System.out.println(max.get());

        Optional<Double> min = lists.stream()
                .map(Employee::getSalary)
                .collect(Collectors.minBy(Double::compare));
        System.out.println(min.get());

    }

    @Test
    public void test9() {
        //分组
        Map<Employee.Status, List<Employee>> collect = lists.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        /*System.out.println(collect);*/
        //分级分组
        Map<Employee.Status, Map<String, List<Employee>>> collect1 = lists.stream()
                .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
                    if (e.getAge() <= 30) {
                        return "青年";
                    } else if (e.getAge() >= 60) {
                        return "老年";
                    } else {
                        return "中年";
                    }
                })));
        Set<Employee.Status> statuses = collect1.keySet();
        for (Employee.Status status : statuses) {
            Map<String, List<Employee>> stringListMap = collect1.get(status);
            System.out.println(status + ":" + stringListMap);
            System.out.println();
        }
    }

    @Test
    public void test10() {
        Map<Boolean, List<Employee>> collect = lists.stream()
                .collect(Collectors.partitioningBy((x) -> x.getSalary() > 6500));
        Set<Boolean> booleans = collect.keySet();
        for (Boolean aBoolean : booleans) {
            List<Employee> employees = collect.get(aBoolean);
            System.out.println(aBoolean + ":" + employees);
            System.out.println();
        }
    }

    @Test
    public void test11() {
        String collect = lists.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(",", "==>", "<=="));
        System.out.println(collect);

        DoubleSummaryStatistics dss = lists.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(dss);
        System.out.println(dss.getMax());
        System.out.println(dss.getAverage());
        System.out.println(dss.getCount());
        System.out.println(dss.getMin());
        System.out.println(dss.getSum());
    }

    /**
     * 案例一：给定一个数字列表，如何返回一个由每个数的平方构成的列表呢？(如：给定【1，2，3，4，5】，返回【1，4，9，16，25】)
     */
    @Test
    public void StreamAPITest1() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> collect = list.stream()
                .map((x) -> x * x)
                .collect(Collectors.toList());
        System.out.println(collect);
    }

    /**
     * 案例二：怎样使用 map 和 reduce 数一数流中有多少个 Employee 呢？
     */
    @Test
    public void StreamAPITest2() {
        Integer reduce = lists.stream()
                .map((x) -> 1)
                .reduce(0, Integer::sum);
        System.out.println(reduce);
    }

    /**
     * 1.找出2011年发生的所有交易，并按交易额排序（从高到底）
     */
    @Test
    public void test03() {

    }

    /**
     * 2.交易员都在哪些不同的城市工作过？
     */
    @Test
    public void test04() {

    }

    /**
     * 3.查找来自剑桥的交易员，并按姓名排序
     */
    @Test
    public void test05() {
    }

    /**
     * 4.返回所有交易员的姓名字符串，并按字母顺序排序
     */
    @Test
    public void test06() {

    }

    /**
     * 5.有没有交易员是在米兰工作的？
     */
    @Test
    public void test07() {

    }

    /**
     * 6.打印生活在剑桥的交易员的所有交易额
     */
    @Test
    public void test08() {

    }

    /**
     * 7.所有交易中，最高的交易额是多少？
     */
    @Test
    public void test09() {

    }

    /**
     * 8.找到交易额最小的交易
     */
    @Test
    public void test010() {

    }


}
